//
// XAPIKLib
//
// kernle dll lib entrys
// reimplement some kernel functions for kernel dll
//
// note: if link to kernel directly, this file is no need
//

//#define IN_KERNEL
#include <kernel.h>

int XAPI_Init();

void _SetCPUASID (PTHREAD);



#define XAPI_IMP_FUNC(Api, Args)     ((g_XAPIImps.p##Api) Args)
#define XAPI_IMP_VAR(var)     (g_XAPIImps.p##var)


#ifndef SHIP_BUILD
#undef RETAILMSG
#define RETAILMSG(cond, printf_exp) ((cond)?(XAPI_IMP_FUNC(NKDbgPrintfW, printf_exp),1):0)
#endif // SHIP_BUILD

#ifdef DEBUG
#undef DEBUGMSG
#define DEBUGMSG                 RETAILMSG
#endif // DEBUG


typedef struct
{
	union{
		CeLogImportTable celogImportTable;
		struct{
			DWORD    dwVersion;               // Version of this structure, set to 4
			FARPROC  pCreateEventW;
			FARPROC  pEventModify;
			FARPROC  pCreateFileMappingW;
			FARPROC  pMapViewOfFile;
			FARPROC  pUnmapViewOfFile;
			FARPROC  pCloseHandle;
			FARPROC  pLockPages;
			FARPROC  pUnlockPages;
			FARPROC  pVirtualAlloc;
			FARPROC  pVirtualFree;
			FARPROC  pMapPtrToProcess;
			FARPROC  pQueryPerformanceCounter;
			FARPROC  pQueryPerformanceFrequency;
			FARPROC  pNKDbgPrintfW;
			FARPROC  pCeLogReSync;
			FARPROC  pGetLastError;
			FARPROC  pSetLastError;
			FARPROC  pGetThreadCallStack;
			FARPROC  pInSysCall;              // Pointer to InSysCall wrapper function
			DWORD   *pdwCeLogTLBMiss;         // Pointer to TLB miss count
			DWORD    dwCeLogLargeBuf;         // OEM-changeable large buffer size
			DWORD    dwCeLogSmallBuf;         // OEM-changeable small buffer size
			DWORD    dwDefaultThreadQuantum;  // The scheduler's default thread quantum
		};
	};
	union{
		CeLogPrivateImports	celogPrivateImports;
		struct{
		    DWORD    dwVersion_celogprivate;             // Version of this structure, set to CELOG_PRIVATE_IMPORT_VERSION
		    FARPROC  pRegQueryValueExW;     // Pointer to NKRegQueryValueExW function
		    FARPROC  pINTERRUPTS_ENABLE;    // Pointer to INTERRUPTS_ENABLE function
		    FARPROC  pPhys2Virt;            // Pointer to Phys2Virt wrapper function
		    FARPROC  pKCall;                // Pointer to KCall function
		    FARPROC  pCeLogData;            // Pointer to kernel's CeLogData entry point
		    struct KDataStruct *pKData;     // Pointer to KData struct
		};
	};
}XAPIImports;

BOOL XAPIInitKLibrary(FARPROC pfnKernelLibIoControl);

XAPIImports g_XAPIImps;

//
// kernel data redefine
//
#define SystemAPISets XAPI_SystemAPISets
CINFO** SystemAPISets;

#define MemoryInfo (*pMemoryInfo)
MEMORYINFO* pMemoryInfo;


// for asm used kernel data
struct KDataStruct* pKData;
SECTION* pNKSection;

BOOL   g_fInit=FALSE;

//------------------------------------------------------------------------------
// DLL entry
//------------------------------------------------------------------------------
BOOL WINAPI
DLLEntry(HINSTANCE DllInstance, INT Reason, LPVOID Reserved)
{
    switch (Reason) {
    case DLL_PROCESS_ATTACH:
        if (!g_fInit) {
            if (Reserved) {
                // Reserved parameter is a pointer to KernelLibIoControl function
                return XAPIInitKLibrary((FARPROC)Reserved);
            }
            // Loaded via LoadLibrary instead of LoadKernelLibrary?
            return FALSE;
        }
        break;

    case DLL_PROCESS_DETACH:
        break;
    }
    
    return TRUE;
}

//------------------------------------------------------------------------------
// Hook up function pointers and initialize logging
//------------------------------------------------------------------------------
BOOL XAPIInitKLibrary(
    FARPROC pfnKernelLibIoControl
    )
{
    //
    // KernelLibIoControl provides the back doors we need to obtain kernel
    // function pointers and register logging functions.
    //
    
    // Get public imports from kernel
    g_XAPIImps.celogImportTable.dwVersion = CELOG_IMPORT_VERSION;
    if (!pfnKernelLibIoControl((HANDLE)KMOD_CELOG, IOCTL_CELOG_IMPORT, &g_XAPIImps.celogImportTable,
                               sizeof(g_XAPIImps.celogImportTable), NULL, 0, NULL)) {
        // Can't DEBUGMSG or anything here b/c we need the import table to do that
        return FALSE;
    }

    // Get private imports from kernel
    g_XAPIImps.celogPrivateImports.dwVersion = CELOG_PRIVATE_IMPORT_VERSION;
    if (!pfnKernelLibIoControl((HANDLE)KMOD_CELOG, IOCTL_CELOG_IMPORT_PRIVATE, &g_XAPIImps.celogPrivateImports,
                               sizeof(g_XAPIImps.celogPrivateImports), NULL, 0, NULL)) {
        DEBUGMSG(1, (TEXT(": Error, private import failed\r\n")));
        XAPI_IMP_FUNC(SetLastError, (ERROR_NOT_SUPPORTED));
        return FALSE;
    }

	SystemAPISets=(CINFO **)XAPI_IMP_VAR(KData)->aInfo[KINX_APISETS];
	pKData=XAPI_IMP_VAR(KData);
	pNKSection=(SECTION*)XAPI_IMP_VAR(KData)->aInfo[KINX_NKSECTION];
	pMemoryInfo=(MEMORYINFO*)XAPI_IMP_VAR(KData)->aInfo[KINX_MEMINFO] ;

	XAPI_Init();

    g_fInit = TRUE;

	return TRUE;
}

//
// mdarm.c
//

void SetCPUASID (PTHREAD pth)
{
    _SetCPUASID (pth);
// not clear slots, so the code can access more slots, and there will be secure problem maybe
//    KCall ((FARPROC) ClearSlots);
}


//
// objdisp.c
//
//------------------------------------------------------------------------------
// Convert a HANDLE to an HDATA pointer.
//
// HandleToPointer() is a function which can be used by other kernel modules.
//
//  h2p() is an private macro used to speed up the internal processing of
// ObjectCall() and the various GetXXX/SetXXX functions.
//------------------------------------------------------------------------------
#define h2p(h, phdRet) \
    do { \
        if ((ulong)h < NUM_SYS_HANDLES+SYS_HANDLE_BASE && (ulong)h >= SYS_HANDLE_BASE) \
             h = KData.ahSys[(uint)h-SYS_HANDLE_BASE]; \
        if (h) {            \
            phdRet = (PHDATA)(((ulong)h & HANDLE_ADDRESS_MASK) + KData.handleBase); \
            if (!IsValidKPtr(phdRet) || phdRet->hValue != h) \
                phdRet = 0; \
        } else              \
            phdRet = 0;     \
    } while (0)


void UpdateCallerInfo (PTHREAD pth, BOOL fInKMode)
{
    PCALLSTACK pcstk = pth->pcstkTop;
    PPROCESS pProc;

    // skip the faked callstacks for exception dispatch
    while (pcstk && ((DWORD) pcstk->pcstkNext & 1)) {
        pcstk = (PCALLSTACK) ((DWORD) pcstk->pcstkNext & ~1);
    }

    pProc = pcstk? pcstk->pprcLast : pth->pOwnerProc;

    KCALLERTRUST(pth) = pProc? pProc->bTrustLevel : KERN_TRUST_FULL;
    KCALLERVMBASE(pth) = pProc? pProc->dwVMBase : SECURE_VMBASE;
    if (fInKMode)
        KTHRDINFO(pth) |= UTLS_INKMODE;
    else
        KTHRDINFO(pth) &= ~UTLS_INKMODE;

    // tlsNonSecure can be 0 in NKTerminateThread
    if ((pth->tlsNonSecure != pth->tlsSecure) && pth->tlsNonSecure){
        pth->tlsNonSecure[PRETLS_THRDINFO] = 0;
    }
}

PVOID 
GetObjectPtrByType(
    HANDLE h,
    int type
    )
{
    PHDATA phd;

    h2p(h, phd);
#ifdef DEBUG
    if (phd && (((PVOID) 0xabababcd == phd->pvObj) || ((PVOID) 0xabababef == phd->pvObj)))
        return 0;
#endif
    return (phd && phd->pci && phd->pci->type==type) ? phd->pvObj : 0;
}

//
// kmisc.c
//
void
SwitchBack()
{
    PCALLSTACK pcstk;
    pcstk = pCurThread->pcstkTop;
    pCurThread->pcstkTop = pcstk->pcstkNext;
    SETCURKEY(pcstk->akyLast);
    pCurThread->pProc = pcstk->pprcLast;
    SetCPUASID(pCurThread);
    UpdateCallerInfo (pCurThread, TRUE);
    ClearNKCallOut (pCurThread);

}

void
DoMapPtr(
    LPVOID *P
    )
{
    if (((DWORD)*P >= 0x10000) && !((DWORD)*P >> VA_SECTION))
        *P = (LPVOID)((DWORD)*P | (DWORD)pCurProc->dwVMBase);
}
